package com.zx.map.service.impl;

import com.zx.map.dao.EncashLogDao;
import com.zx.map.dao.model.EncashLog;
import com.zx.map.dao.model.EncashLogExample;
import com.zx.map.service.*;
import com.zx.map.service.model.*;
import com.zx.mobile.PayRateHelper;
import com.zx.mobile.domain.EncashQueryDomain;
import com.zx.mobile.service.proxy.EncashCommonProxy;
import com.zx.platform.utils.DateUtils;
import com.zx.platform.utils.PmpUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.util.*;

/**
 * Created by IntelliJ IDEA. User: Administrator Date: 14-3-1 Time: 上午11:07 To
 * change this template use File | Settings | File Templates.
 */
@Component("encashLogService")
public class EncashLogServiceImpl implements EncashLogService {
    /**
     * log
     */
    private static Logger log = Logger.getLogger(EncashLogServiceImpl.class);

    @Autowired
    private EncashLogDao dao;
    @Autowired
    private RemoteIntefaceVisitService remoteIntefaceVisitService;
    @Autowired
    private BaseAcctInfoService baseAcctInfoService;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private SummaryInfoService summaryInfoService;
    @Autowired
    private SettleCardInfoService settleCardInfoService;
    @Autowired
    private MerchantInfoService merchantInfoService;
    @Autowired
    private CustAcctLogService custAcctLogService;
    @Autowired
    private AgentInfoService agentInfoService;

    /**
     * T+1出款
     */
    public EncashResponse dealEncashLogT1(final EncashLogModel encashLogModel, final SettleCardInfoModel settleCardInfoModel) {
        EncashResponse encashResponse = (EncashResponse) transactionTemplate.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(TransactionStatus arg0) {
                EncashResponse encashResponse = new EncashResponse();
                //无论任何情况下  均先扣减虚拟账户资金  并增加行锁
                BaseAcctInfoModel temp = baseAcctInfoService.getModelByKeyAndLineLock(settleCardInfoModel
                        .getSubjectId());
                if (temp.getAvlBal() >= encashLogModel.getEncashAmt()) {
                    // T1取现 账户余额减少
                    temp = EncashCommonProxy.transformSubBaseAcct(temp,
                            encashLogModel.getEncashAmt().toString());
                    CustAcctLogModel custModel = EncashCommonProxy.transformCustAcct(temp, encashLogModel);
                    custAcctLogService.add(custModel);
                   // baseAcctInfoService.update(temp);
                    //1、增加取现记录
                    add(encashLogModel);
                    encashResponse.setReturnCode("0000");
                } else {
                    encashResponse.setErrMsg("取现金额超过可用余额");
                    encashResponse.setReturnCode("9999");
                }
                return encashResponse;
            }
        });
        return encashResponse;

    }

    /**
     * T+0实时出款
     */
    public EncashResponse dealEncashLogT0(final EncashLogModel encashLogModel,
                                          final SettleCardInfoModel settleCardInfoModel) {
        //检查T0额度
        SummaryInfoModel summaryInfoModel = summaryInfoService.getMerchantTOUseSummary(settleCardInfoModel
                .getSubjectId());
        BigDecimal sumToUseAmt = new BigDecimal(String.valueOf(summaryInfoModel.getSumAmt()));
        //加上当前取现金额 判断是否超限
        sumToUseAmt = sumToUseAmt.add(new BigDecimal(encashLogModel.getEncashAmt().toString()));
        //获取用户默认额度
        MerchantInfoModel merchantInfoModel = merchantInfoService.getModelByKey(settleCardInfoModel.getSubjectId());
        Double tolimitMerchant = merchantInfoModel.getT0Limit();
        //如果商户自己设置了T0额度  使用该额度  如未设置 使用系统默认额度
        Double toLimit = tolimitMerchant == null ? PayRateHelper.ENCASHT0LIMIT : tolimitMerchant;
        if (sumToUseAmt.doubleValue() > (toLimit * 10000)) {
            throw new RuntimeException("T0实时出款额度超限");
        } else {
            EncashResponse encashResponse = (EncashResponse) transactionTemplate.execute(new TransactionCallback<Object>() {
                @Override
                public Object doInTransaction(TransactionStatus arg0) {
                    EncashResponse encashResponse = new EncashResponse();
                    //0、增加取现记录
                    add(encashLogModel);
                    // 1、计算出款金额//小于限定金额 均收取单笔费用
                    BigDecimal transAmt = caculateToAmt(encashLogModel.getEncashAmt());
                    if (transAmt.doubleValue() > 0) {
                        BaseAcctInfoModel baseAcct = baseAcctInfoService
                                .getModelByKeyAndLineLock(settleCardInfoModel
                                        .getSubjectId());
                        //判断额度是否足够
                        if (baseAcct.getAvlBal() >= encashLogModel.getEncashAmt()) {
                            //1、优先扣减取现金额
                            baseAcct = EncashCommonProxy.transformSubBaseAcct(baseAcct,
                                    encashLogModel.getEncashAmt().toString());
                            //增加资金流水记录
                            CustAcctLogModel custModel = EncashCommonProxy.transformCustAcct(baseAcct, encashLogModel);
                            custAcctLogService.add(custModel);
                            baseAcctInfoService.update(baseAcct);
                            //2 以招行银企直连出款 金额为元
                            try {//确保在任何情况下  均实现扣款  我方不短款
                                OutcomeResponse response = remoteIntefaceVisitService
                                        .outComeSingleByCmb(transAmt.toString(), encashLogModel.getEncashId(), settleCardInfoModel);
                                // 3.得到返回数据并处理  0000 明确成功  9000 银行明确失败  9999 失败
                                if (null != response) {
                                    log.info("出款服务调用返回:" + ToStringBuilder.reflectionToString(response));
                                    encashResponse.setReturnCode(response.getReturnCode());
                                    encashResponse.setErrMsg(response.getErrMsg());
                                    String tradeStatus = "0000".equals(response.getReturnCode()) ? "S" : "F";
                                    encashLogModel.setSettleStatus(tradeStatus);
                                    encashLogModel.setEncashStatus(tradeStatus);
                                    encashLogModel.setSettleOrdId(response.getSettleOrdId());
                                    encashLogModel.setSettleTime(DateUtils.dateToString(new Date(),
                                            "yyyyMMddHHmmss"));
                                    encashLogModel.setSettleRemark(response.getSettleDay() + response.getReturnCode() + response.getErrMsg());
                                    encashLogModel.setSettleAmt(transAmt.doubleValue());
                                    // 0000 明确成功  9000 银行明确失败  9999 失败
                                    if ("9000".equals(response.getReturnCode())) {
                                        log.info("银行明确失败 需要资金退回");
                                        //资金回退  原始锁定记录
                                        baseAcct = EncashCommonProxy.transformAddBaseAcct(baseAcct,
                                                encashLogModel.getEncashAmt().toString());
                                        custModel = EncashCommonProxy.transformReverseCustAcct(baseAcct, encashLogModel);
                                        custAcctLogService.add(custModel);
                                        baseAcctInfoService.update(baseAcct);
                                    }
                                    update(encashLogModel);
                                    return encashResponse;
                                } else {
                                    log.info("T0实时出款处理失败:"
                                            + ToStringBuilder.reflectionToString(response));
                                    encashResponse.setErrMsg("T0实时出款处理失败");
                                    encashResponse.setReturnCode("9999");
                                }
                            } catch (Exception e) {
                                log.error("实时取现出现问题", e);
                                encashResponse.setErrMsg("实时取现出现问题");
                                encashResponse.setReturnCode("9999");
                            }
                        } else {
                            encashResponse.setErrMsg("取现金额超过可用余额");
                            encashResponse.setReturnCode("9999");
                        }
                    } else {
                        log.info("申请金额过低不处理");
                        encashResponse.setReturnCode("9999");//提示取现已经受理
                        encashResponse.setErrMsg("取现金额过低");
                    }
                    return encashResponse;
                }

                private BigDecimal caculateToAmt(Double encashAmt) {
                    BigDecimal encachAmt = new BigDecimal(encashAmt);
                    BigDecimal deductAmt = new BigDecimal("0");// 需要扣除金额
                    /*1. T0收费由原来的0.15%调整为0.1%；
                    2. 2元的代付费调整统一都收（原来是5000以下客户自己承担，5000以上我们承担）；
                                                                              第2条应该已经处理过了。而且原来是0.12%，不是0.15%，可能之前也有开发改过edit by wenjw 2017.1.9
                    *
                    */
//                    if (encachAmt.compareTo(new BigDecimal(PayRateHelper.ENCASHLIMITAMT)) <= 0) {
                    //每笔扣除2元
                    deductAmt = deductAmt
                            .add(new BigDecimal(PayRateHelper.ENCASHAMTPER));
//                    }
                    // T0收取固定手续费
                    deductAmt = deductAmt.add(encachAmt.multiply(new BigDecimal(
                            PayRateHelper.ENCASHRATE))).setScale(2, BigDecimal.ROUND_UP);
                    BigDecimal transAmt = encachAmt.subtract(deductAmt).setScale(2, BigDecimal.ROUND_DOWN);
                    log.info("申请金额:" + encachAmt + "	扣费部分：" + deductAmt);
                    return transAmt;
                }
            });
            return encashResponse;
        }/**/

    }

    /**
     * 分页查询

     * @return
     * @throws DataAccessException
     */
    public Map getPageByDomain(AgentInfoModel curAgentInfoModel, EncashQueryDomain encashQueryDomain)
            throws DataAccessException {
        Map<String, Object> map = new HashMap<String, Object>();
        EncashLogExample example = new EncashLogExample();
        EncashLogExample.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotBlank(encashQueryDomain.getMerchantId())) {
            criteria.andMerchantIdEqualTo(encashQueryDomain.getMerchantId());
        }
        if (StringUtils.isNotBlank(encashQueryDomain.getMerSysAccount())) {
            criteria.andMerSysAccountEqualTo(encashQueryDomain.getMerSysAccount());
        }
        if (StringUtils.isNotBlank(encashQueryDomain.getEncashAmt())) {
            criteria.andEncashAmtEqualTo(Double.valueOf(encashQueryDomain
                    .getEncashAmt()));
        }
        if (StringUtils.isNotBlank(encashQueryDomain.getEncashType())) {
            criteria.andEncashTypeEqualTo(encashQueryDomain.getEncashType());
        }
        if (StringUtils.isNotBlank(encashQueryDomain.getBeginDate())) {
            criteria.andCreateDateBetween(PmpUtils.strToDate(
                    encashQueryDomain.getBeginDate(), "yyyy-MM-dd"), PmpUtils
                    .addDate(PmpUtils.strToDate(encashQueryDomain.getEndDate(),
                            "yyyy-MM-dd"), 1));
        }
        if(StringUtils.isNotBlank(encashQueryDomain.getAgentId())) {
        	//查出所有子节点，包含自己
			List<String> values = agentInfoService.queryDownAgentIdList(curAgentInfoModel);
			if(values==null||values.size()==0){
				values = new ArrayList();
				values.add("-1");
	       	}
			criteria.andAgentIdIn(values);
        }
        int pageBegin = (encashQueryDomain.getPageNum() - 1) * encashQueryDomain.getPageSize();
        List<EncashLog> list = dao.getPageByExample(encashQueryDomain.getPageSize(), pageBegin, example);
        List<EncashLogModel> modelList = new ArrayList<EncashLogModel>();
        for (EncashLog o : list) {
            EncashLogModel temp = new EncashLogModel();
            BeanUtils.copyProperties(o, temp);
            modelList.add(temp);
        }
        int count = dao.countListByExample(example);
        double settleAmt = dao.getSettleAmt(example);
        map.put("settleAmt", settleAmt);
        map.put("count", count);
        map.put("list", modelList);
        return map;
    }

    /**
     * 订单查询条件获取交易信息
     * 后端查询服务  主要是查询条件日期YYYY-MM-DD
     *
     * @param encashQueryDomain
     * @return
     * @throws org.springframework.dao.DataAccessException
     */
    public List<EncashLogModel> getListByDomainForManage(
            EncashQueryDomain encashQueryDomain) throws DataAccessException {
        EncashLogExample example = new EncashLogExample();
        EncashLogExample.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotBlank(encashQueryDomain.getMerchantId())) {
            criteria.andMerchantIdEqualTo(encashQueryDomain.getMerchantId());
        }
        if (StringUtils.isNotBlank(encashQueryDomain.getEncashAmt())) {
            criteria.andEncashAmtEqualTo(Double.valueOf(encashQueryDomain
                    .getEncashAmt()));
        }
        if (StringUtils.isNotBlank(encashQueryDomain.getMerSysAccount())) {
            criteria.andMerSysAccountEqualTo(encashQueryDomain.getMerSysAccount());
        }
        if (StringUtils.isNotBlank(encashQueryDomain.getEncashType())) {
            criteria.andEncashTypeEqualTo(encashQueryDomain.getEncashType());
        }
        if (StringUtils.isNotBlank(encashQueryDomain.getBeginDate())) {
            criteria.andCreateDateBetween(PmpUtils.strToDate(
                    encashQueryDomain.getBeginDate(), "yyyy-MM-dd"), PmpUtils
                    .addDate(PmpUtils.strToDate(encashQueryDomain.getEndDate(),
                            "yyyy-MM-dd"), 1));
        }
        List<EncashLog> list = dao.getListByExample(example);
        List<EncashLogModel> modelList = new ArrayList<EncashLogModel>();
        for (EncashLog o : list) {
            EncashLogModel temp = new EncashLogModel();
            BeanUtils.copyProperties(o, temp);
            modelList.add(temp);
        }
        return modelList;
    }

    /**
     * 订单查询条件获取交易信息
     * 前端查询调用 主要是查询条件日期YYYYMMDD
     *
     * @param encashQueryDomain
     * @return
     * @throws org.springframework.dao.DataAccessException
     */
    public List<EncashLogModel> getListByDomain(
            EncashQueryDomain encashQueryDomain) throws DataAccessException {
        EncashLogExample example = new EncashLogExample();
        EncashLogExample.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotBlank(encashQueryDomain.getMerchantId())) {
            criteria.andMerchantIdEqualTo(encashQueryDomain.getMerchantId());
        }
        if (StringUtils.isNotBlank(encashQueryDomain.getEncashAmt())) {
            criteria.andEncashAmtEqualTo(Double.valueOf(encashQueryDomain
                    .getEncashAmt()));
        }
        if (StringUtils.isNotBlank(encashQueryDomain.getEncashType())) {
            criteria.andEncashTypeEqualTo(encashQueryDomain.getEncashType());
        }
        if (StringUtils.isNotBlank(encashQueryDomain.getBeginDate())) {
            criteria.andCreateDateBetween(PmpUtils.strToDate(
                    encashQueryDomain.getBeginDate(), "yyyyMMdd"), PmpUtils
                    .addDate(PmpUtils.strToDate(encashQueryDomain.getEndDate(),
                            "yyyyMMdd"), 1));
        }
        List<EncashLog> list = dao.getListByExample(example);
        List<EncashLogModel> modelList = new ArrayList<EncashLogModel>();
        for (EncashLog o : list) {
            EncashLogModel temp = new EncashLogModel();
            BeanUtils.copyProperties(o, temp);
            modelList.add(temp);
        }
        return modelList;
    }


    /**
     * 根据Model查找列表
     */
    public List<EncashLogModel> getListByModel(EncashLogModel model)
            throws DataAccessException {
        EncashLogExample example = new EncashLogExample();
        EncashLogExample.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotBlank(model.getMerchantId())) {
            criteria.andMerchantIdEqualTo(model.getMerchantId());
        }
        if (null != model.getEncashAmt()) {
            criteria.andEncashAmtEqualTo(Double.valueOf(model
                    .getEncashAmt()));
        }
        if (StringUtils.isNotBlank(model.getEncashType())) {
            criteria.andEncashTypeEqualTo(model.getEncashType());
        }
        if (StringUtils.isNotBlank(model.getEncashDay())) {
            criteria.andEncashDayEqualTo(model.getEncashDay());
        }
        if (StringUtils.isNotBlank(model.getEncashStatus())) {
            criteria.andEncashStatusEqualTo(model.getEncashStatus());
        }
        if (StringUtils.isNotBlank(model.getSettleStatus())) {
            criteria.andSettleStatusEqualTo(model.getSettleStatus());
        }
        List<EncashLog> list = dao.getListByExample(example);
        List<EncashLogModel> modelList = new ArrayList<EncashLogModel>();
        for (EncashLog o : list) {
            EncashLogModel temp = new EncashLogModel();
            BeanUtils.copyProperties(o, temp);
            SettleCardInfoModel settleCardInfoParam = new SettleCardInfoModel();
            settleCardInfoParam.setSubjectId(temp.getMerchantId());
            SettleCardInfoModel settleCardInfoModel = settleCardInfoService.getModelByInfo(settleCardInfoParam);
            temp.setSettleCardInfoModel(settleCardInfoModel);
            modelList.add(temp);
        }
        return modelList;
    }

    /**
     * 新增
     */
    public String add(EncashLogModel model) throws DataAccessException {
        EncashLog temp = new EncashLog();
        BeanUtils.copyProperties(model, temp);
        String key = dao.add(temp);
        return key;
    }

    /**
     * 修改
     */
    public String update(EncashLogModel model) throws DataAccessException {
        EncashLog temp = new EncashLog();
        BeanUtils.copyProperties(model, temp);
        return dao.update(temp);
    }

    /**
     * 删除
     */
    public void delete(EncashLogModel model) throws DataAccessException {
        EncashLog temp = new EncashLog();
        BeanUtils.copyProperties(model, temp);
        dao.delete(temp);
    }

    /**
     * 根据筛选的记录 更新某个字段
     */
    public void updateEncashLogBySelect(EncashLogModel encashLog, EncashLogModel modelSelected) {
        EncashLogExample example = new EncashLogExample();
        EncashLogExample.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotBlank(modelSelected.getMerchantId())) {
            criteria.andMerchantIdEqualTo(modelSelected.getMerchantId());
        }
        if (null != modelSelected.getEncashAmt()) {
            criteria.andEncashAmtEqualTo(Double.valueOf(modelSelected
                    .getEncashAmt()));
        }
        if (StringUtils.isNotBlank(modelSelected.getEncashType())) {
            criteria.andEncashTypeEqualTo(modelSelected.getEncashType());
        }
        if (StringUtils.isNotBlank(modelSelected.getEncashDay())) {
            criteria.andEncashDayEqualTo(modelSelected.getEncashDay());
        }
        if (StringUtils.isNotBlank(modelSelected.getEncashStatus())) {
            criteria.andEncashStatusEqualTo(modelSelected.getEncashStatus());
        }
        if (StringUtils.isNotBlank(modelSelected.getSettleStatus())) {
            criteria.andSettleStatusEqualTo(modelSelected.getSettleStatus());
        }
        EncashLog temp = new EncashLog();
        BeanUtils.copyProperties(encashLog, temp);
        dao.updateByExample(temp, example);
    }

    /**
     * 查询特定时间段内是否包含数据
     *
     * @param model
     * @param delayTime
     * @return
     * @throws DataAccessException
     */
    public List<EncashLogModel> getListPeriodByModel(EncashLogModel model, int delayTime) throws DataAccessException {
        EncashLogExample example = new EncashLogExample();
        EncashLogExample.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotBlank(model.getMerchantId())) {
            criteria.andMerchantIdEqualTo(model.getMerchantId());
        }
        if (null != model.getEncashAmt()) {
            criteria.andEncashAmtEqualTo(Double.valueOf(model
                    .getEncashAmt()));
        }
        if (StringUtils.isNotBlank(model.getEncashType())) {
            criteria.andEncashTypeEqualTo(model.getEncashType());
        }
        if (StringUtils.isNotBlank(model.getEncashDay())) {
            criteria.andEncashDayEqualTo(model.getEncashDay());
        }
        if (StringUtils.isNotBlank(model.getEncashStatus())) {
            criteria.andEncashStatusEqualTo(model.getEncashStatus());
        }
        //增加时间段检索
        Date nowDate = new Date();
        criteria.andCreateDateBetween(DateUtils.addDateByMinute(new Date(), 0 - delayTime), nowDate);
        List<EncashLog> list = dao.getListByExample(example);
        List<EncashLogModel> modelList = new ArrayList<EncashLogModel>();
        for (EncashLog o : list) {
            EncashLogModel temp = new EncashLogModel();
            BeanUtils.copyProperties(o, temp);
            modelList.add(temp);
        }
        return modelList;
    }
}
